package org.framework.app.model.dao;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import net.pgia.pub.util.UtilException;
import net.pgia.pub.util.common.ObjectUtil;
import net.pgia.pub.util.common.StringUtil;

import org.apache.log4j.Logger;
import org.framework.app.exception.AppException;
import org.framework.app.exception.SysException;
import org.framework.sys.SysConfigDef;
import org.framework.sys.SysConfigReader;


/**
 * Abstract class for dao factory <br>
 * Apr 18, 2007 9:17:25 PM
 * 
 * @author liaoyh
 */
public class DAOFactory {
	private static Logger log = Logger.getLogger(DAOFactory.class);
	
		
	private static String DAO_MAP_FILE_NAME = "daoMapFile.properties";
	
	private static final String DOM_IMPL_SUFFIX = "Impl";

	private static final String SEPARATOR = ".";
	
	private static DAOFactory instance;
	
	String runMode = SysConfigReader.getSysConfigDef().getRunMode();
	
	private static String dbDialect  = "oracle";
	
	private static String DAO_IMPL_SUFFIX = "Impl";

	
	//缓存DAO实现类实例
	private Map daoImplCache = new HashMap();

	private DAOFactory() throws AppException, SysException{
		
		SysConfigDef pro = SysConfigReader.getSysConfigDef();
		runMode = pro.getRunMode();
		
		//生产模式进行dao映射文件装载
		if(!SysConfigDef.RUN_MODE_DEBUG.equals(runMode)){
			InputStream is = null;		
			is = DAOFactory.class.getClassLoader().getResourceAsStream(DAO_MAP_FILE_NAME);
			
			Properties prop = readProperties(is);
			daoImplCache = this.getDAOImpls(prop);
		}
	}
	/**
	 * 获取DAO工厂实例，没有则创建新实例
	 * @param path
	 * @return
	 * @throws SysException 
	 * @throws AppException 
	 */
	synchronized public static DAOFactory initDAOFactory() throws AppException, SysException{
		if(null == instance){
			instance = new DAOFactory();
		}
		return instance;
	}
	/**
	 * 读取配置文件配置
	 * 
	 * @param is
	 * @throws AppException
	 * @throws SysException
	 */
	private Properties readProperties(InputStream is) throws AppException, SysException {
		if (null == is)
			throw new AppException("100005", "系统未获取到DAO接口实现类映射关系文件！");
		Properties config = new Properties();
		try {
			config.load(is);
			return config;
		} catch (IOException e) {
			throw new SysException("100005", "系统装载DAO接口实现类映射关系文件失败！",e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					throw new SysException("100005", "系统关闭配置读取控制错误！", e);
				}
			}
		}
	}
	
	
	/**
	 * 根据配置创建Map<dao接口名-dao实现对象>
	 * @param prop
	 * @return
	 * @throws AppException
	 * @throws SysException
	 */
	private Map getDAOImpls(Properties prop) throws AppException, SysException {
		Map DAOImpls = new HashMap();
		
		if(prop != null){
			 Enumeration emr =prop.propertyNames(); 
			 while(emr.hasMoreElements()){
				 String daoInterfaceName = (String)emr.nextElement();
				 String daoImplName = prop.getProperty(daoInterfaceName);
				 try {
					 	Object impl = ObjectUtil.createByName(daoImplName);
						DAOImpls.put(daoInterfaceName, impl);
					} catch (UtilException e) {
						log.error( daoImplName + "实现类反射创建错误!"+e.getMessage());
						continue;
					}
			 }
		}
		
		return  DAOImpls ;
		
	}

	/**
	 * 获取Debug模式下的DAO实现类 
	 * Debug模式下，直接通过dao接口类获取对应的实现
	 * 
	 * @param DelegateClass
	 * @throws AppException
	 * @throws SysException
	 */
	public static IDAO getDaoDebugMode(Class iDaoClass) throws AppException, SysException {
		
		IDAO daoImpl = null;
		log.debug(iDaoClass.getPackage().getName());
		log.debug(iDaoClass.getName());
		
		String domImplName1 = iDaoClass.getPackage().getName()+".daoImpl."+iDaoClass.getSimpleName();
		StringBuffer className = new StringBuffer(domImplName1);
		int i = className.lastIndexOf(SEPARATOR);

		
		className.append(DOM_IMPL_SUFFIX);
		className.deleteCharAt(i + 1);
		   	
		
		String DomImplName = className.toString();
		log.debug(className);
		try {
			daoImpl = (IDAO) ObjectUtil.createByName(DomImplName);
		} catch (UtilException e) {
			log.error(DomImplName + e.getMessage());
			throw new SysException("", DomImplName + "实例化错误！",e);
		}
		return daoImpl;
	}
	
	/**
	 * 获取DAO工厂实例
	 * @return
	 * @throws AppException 
	 */
	synchronized public static DAOFactory initInstance() throws AppException{
		if(null == instance){
			instance = new DAOFactory();
		}
		return instance;
	}
	 
	/**
	 * 通过DAO接口类获取对应的DAO实现
	 * @param DAOClass
	 * @return
	 * @throws AppException 
	 * @throws SysException 
	 */
	public static IDAO getDAO(Class DAOClass) throws AppException, SysException{
		
		if( null == DAOClass){
			throw new AppException("","无效的参数Null！");
		}
		if(null == instance){
			initInstance();
		}
		if(SysConfigDef.RUN_MODE_DEBUG.equals(instance.runMode)){
			return getDaoDebugMode(DAOClass);
		}
		
		Object daoImpl = instance.daoImplCache.get(DAOClass.getName());
		if(null == daoImpl){
			//DEBUG模式动态反射创建DAO实例
			if(SysConfigDef.RUN_MODE_DEBUG.equals(instance.getRunMode())){
				daoImpl = instance.getDAODebugMode(DAOClass);
			}else{
				throw new AppException("","找不到接口对应的实现类！["+DAOClass.getName()+"]");
			}
		}

		if(null == daoImpl){
			throw new AppException("100003","找不到接口对应的DAO实现类。"+DAOClass.getName());
		}
		return (IDAO)daoImpl;
	}
	
	
	public  IDAO getDAODebugMode(Class interfaceDaoName){
		
		if(null == interfaceDaoName) return null;
		
		String aDAOInterface = interfaceDaoName.getSimpleName();
		int classNameIndexStart = interfaceDaoName.getName().lastIndexOf(".");
		
		String dbDialet = this.dbDialect;
		
		String interfaceCatalog = StringUtil.subString(interfaceDaoName.getName(), classNameIndexStart);
		String DAOInterfacePrefix = interfaceCatalog + ".";
		String DAOImplPrefix = interfaceCatalog + "." + dbDialet + this.DAO_IMPL_SUFFIX + ".";
		// 接口名和实现名
		String DAOInterfaceName = DAOInterfacePrefix + aDAOInterface;
		String DAOImplName = DAOImplPrefix + aDAOInterface.substring(1);// 去掉接口标识“I”

		IDAO impl = null;
		// 去掉后面的.class
		try {
			// 实现名称加上Impl后缀
			DAOImplName = DAOImplName + this.DAO_IMPL_SUFFIX;
			Object implObj = ObjectUtil.createByName(DAOImplName);
			impl = (IDAO)implObj;
			//log.debug("成功装载DAO:"+DAOImplName);
			//log.debug("map key:"+DAOInterfaceName);
		} catch (UtilException e) {
			log.error( DAOImplName + "文件装载错误!"+e.getMessage());
		}
		
		return impl;
	}
	
	public String getRunMode() {
		return runMode;
	}

	public void setRunMode(String runMode) {
		this.runMode = runMode;
	}
	
	 public static void main(String[] args ) throws Exception{
		 /*SysConfigReader.init("E:/workspace/projects-in-job/fast-projects/pub/src/fast-config.xml");
		 IAreaMDAO dao = (IAreaMDAO)DAOFactory.getDAO(IAreaMDAO.class);
		 System.out.println(dao);*/
		 /*LogConfig.init();
		 DAOFactory.initDAOFactory("dao_config.properties");
		 ConnectionFactory.createConnection();
		 ILocalNetSDAO dao = (ILocalNetSDAO)DAOFactory.getDAO(ILocalNetSDAO.class);
		 LocalNetSVO localNet = new LocalNetSVO();
		 localNet.setLocalNetId("111");
		 localNet.setName("石家庄");
		 
		try{
			dao.delete(localNet);
		
		}finally{
			ConnectionFactory.closeConnection();
		}*/
		/*URL dao_url = Thread.currentThread().getContextClassLoader().getResource("");
		 System.out.println(dao_url);
		 String path = dao_url.getPath();
		 path = path + "../lib/wm.jar";
		 System.out.println(path);
		 JarFile jfile = new JarFile(path);
		
			Enumeration enu = jfile.entries();
			while(enu.hasMoreElements()){
				JarEntry entry = (JarEntry)enu.nextElement();
				System.out.println(entry.getName());
			}*/
		 
		//LogConfig.init();
		//DAOFactory.initDAOFactory("dao_config.properties");
		 //DAOFactory.getDAO(IStepConfigMDAO.class);
			
			/*String[] str = "com/cattsoft/wm/component/dao/oracleImpl/TMsActionSDAOImpl.class".split("com/cattsoft/wm/componsdent/dao/oracleImpl/");
			System.out.println(str[0]);*/
			//System.out.println(str[1]);
			//System.out.println(str[1].substring(0,str[1].length()-6));
		 
	 }

	
	 
}
